/*
Automatic clinic tests using a robot arm.
Copyright (C) 2010  CIC-CPC, CHU Gabriel Montpied
All other trademarks, logos and copyrights are the property
of their respective owners.

This file is part of cpc-painbot.

cpc-painbot is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

cpc-painbot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with cpc-painbot.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "seuil/methode/upanddown.h"

#include <QDebug>

#include "stimulation/stimulateur.h"
#include "stimulation/vonfrey.h"
#include "seuil/determination.h"

#include "rack.h"
#include "filament.h"

namespace seuil {
namespace methode {

UpAndDown::UpAndDown(QObject *parent) :
    Methode(Methode::UpAndDown, parent),
    rack_(0)
{
}

QVariant UpAndDown::valeur() const
{
    QList<qreal> ouis = douleurs_.values(true);
    QList<qreal> nons = douleurs_.values(false);
    qreal valeur = -1;

    qDebug() << "Liste des nons :";
    foreach (qreal non, nons)
        qDebug() << '\t' << non;

    qDebug() << "Liste des ouis :";
    foreach (qreal oui, ouis)
        qDebug() << '\t' << oui;

    // Application de l'algorithme décrit dans l'en-tête.
    if ( !ouis.isEmpty() && !nons.isEmpty() ) {
        if ( ouis.size() > 1 ) {
            qDebug() << "Up and Down, seuil = (" << ouis.first() << '+' << ouis.last() << ") / 2";
            valeur = (ouis.first() + ouis.last()) / 2;
        }//else // cas d'une erreur de confirmation (géré à l'initialisation de la valeur).
        //    valeur = -1;
    } else {
        if (ouis.isEmpty())
            valeur = std::numeric_limits<qreal>::max();
        else
            valeur = 0;
    }

    return valeur;
}

void UpAndDown::determiner()
{
    // Connection des différents signaux.
    // (aucun signal à connecter)

    // Choix de l'Outil (du Filament en l'occurence) sur le Rack.
    // Création de l'itérateur sur le Rack.
    //VonFrey *vf = qobject_cast<VonFrey*>(determination()->stimulateur());
    rack_iter_ = rack()->iterateur();
    //vf->setFilament(*rack_iter_);
    determination()->stimulateur()->setOutil(*rack_iter_);
    douleurs_.clear();
    setPhase(Up);
    setTerminee(false);
}

void UpAndDown::douleur(const QVariant &douleur)
{
    Q_CHECK_PTR(determination());
    Q_CHECK_PTR(determination()->stimulateur());
    Q_ASSERT(douleur.canConvert(QVariant::Bool));

    Stimulateur *stimulateur = determination()->stimulateur();
    douleurs_.insert(douleur.toBool(), stimulateur->outil()->valeur());

    switch (phase()) {
        case Up:
            // Douleur : Augmenter l'intensité, confirmer.
            // Pas de Douleur : Augmenter l'intensité.
            if ( rack_iter_ != rack()->fin() && ++rack_iter_ != rack()->fin() ) {
                qDebug() << "Up and Down : outil supérieur";
                stimulateur->setOutil(*rack_iter_);

                if ( douleur.toBool() )
                    setPhase(Confirmation);

                emit continuer();
            } else {
                qWarning() << "UpAndDown : Pas assez de Filaments (Up)";
                setErreur("Up: manque de filaments.");
            }
            break;

        case Confirmation:
            // Douleur : Diminue l'intensité, Phase down.
            // Pas de Douleur : Une erreur.
            if ( douleur.toBool() ) {
                if ( rack_iter_ != rack()->fin() && --rack_iter_ != rack()->fin() ) {
                    qDebug() << "Up and Down : outil inférieur";
                    stimulateur->setOutil(*rack_iter_);
                } else
                    qWarning() << "UpAndDown : Pas assez de Filaments (Confirmation)";
                setPhase(Down);
                emit continuer();
            } else {
                // Erreur
                setErreur("confirmation");
            }
            break;

        case Down:
            // Douleur : Baisser l'intensité.
            // Pas de Douleur : Fin.
            if ( douleur.toBool() ) {
                if ( rack_iter_ != rack()->fin() && --rack_iter_ != rack()->fin() ) {
                    qDebug() << "Up and Down : outil inférieur";
                    stimulateur->setOutil(*rack_iter_);
                    emit continuer();
                } else {
                    qWarning() << "UpAndDown : Pas assez de Filaments (Down)";
                    setErreur("Down: manque de filaments.");
                }
            } else
                setTerminee(true);
            break;

        default: break;
    }
}

} // namespace methode
} // namespace seuil
